﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;

using Microsoft.Cci;
using SimpleIR;

namespace CCITranslator
{
	[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
	public static class WalkTypeDef
	{
		private static IRProgram s_irprog;
		private static IRType s_currentProcType;
		private static IRInvokeIdentity s_currInvoke;
		private static IMethodDefinition s_currMethod;
		private static PdbReader s_currpdb;
		private static IRSourceLocation s_prevloc;
		private static CCILoader s_loader;

		public static void DoneWalking()
		{
			s_irprog = null;
			s_currentProcType = null;
			s_currInvoke = null;
			s_currMethod = null;
			s_currpdb = null;
			s_prevloc = null;
			s_loader = null;
		}

		/// <summary>
		/// Given a single partially instantiated type, finish by processing the full type definition
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
		internal static void ProcessCompleteType(IRType tt, ITypeDefinition td, IRProgram loadinto, CCILoader ldr)
		{
			s_irprog = loadinto;
			s_currentProcType = tt;
			s_loader = ldr;

			s_currpdb = s_loader.GetPDBForType(td);

			if((!tt.TypeDescription.IsBuiltinType) && (!(tt is IRPrimitiveType)))
				Console.WriteLine("Processing Type: " + tt.ToString());

			if(tt is IRNumericType || tt is IRStructType)
				s_loader.InstantiateBoxAndPointerTypeForValueType((IRValueType)tt);

			////////
			//We may have seen many of these fields previously, but we go over all of them here to make sure everything has been instantiated
			//if((!tt.TypeDescription.IsBuiltinType) && (!(tt is IRPrimitiveType)))
			//	Console.WriteLine("  Processing Fields:");

			foreach(INestedTypeDefinition tydef in td.NestedTypes)
				s_loader.VisitType(tydef);

			foreach(IFieldDefinition fieldDef in td.Fields)
			{
				//if((!tt.TypeDescription.IsBuiltinType) && (!(tt is IRPrimitiveType)))
				//	Console.WriteLine("    Field: " + fieldDef.Name.Value);

				bool markedasskipr = fieldDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.DummyPrimitiveFieldAttribute"));
				if(markedasskipr)
					continue;

				IRType fty = s_loader.VisitType(fieldDef.Type);
				if(fieldDef.IsStatic)
					s_irprog.InternNewStaticFieldFull(tt, fieldDef.Name.Value, fty);
				else
				{
					SpecialFieldTag sff = ExtractFieldTag(fieldDef);
					FieldQualifiers qual = ExtractFieldQual(fieldDef);
					tt.TypeDescription.LoadFieldInfoAsNeeded(tt, fieldDef.Name.Value, fty, sff, qual);
				}
			}
			tt.ProcessBuiltinInfoAsNeeded();

			foreach(ITypeReference baseType in td.BaseClasses)
			{
				if(!tt.TypeName.Equals("System.Object"))
				{
					IRType fty = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(baseType));
					tt.TypeDescription.AllInheritsExtends.Add(fty);
				}
			}

			if(!tt.TypeName.Equals("System.Object"))
				tt.TypeDescription.AllInheritsExtends.Add(s_irprog.TypeTable.RootObjectType);

			foreach(ITypeReference intfType in td.Interfaces)
			{
				IRType fty = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(intfType));
				tt.TypeDescription.AllInheritsExtends.Add(fty);
			}

			//if((!tt.TypeDescription.IsBuiltinType) && (!(tt is IRPrimitiveType)))
			//	Console.WriteLine("  Processing Methods:");

			List<IRVirtualInvoke> declmethods = new List<IRVirtualInvoke>();
			Dictionary<Tuple<IRType, IRInvokeSig>, IRVirtualInvoke> explicitoverridemap = new Dictionary<Tuple<IRType, IRInvokeSig>, IRVirtualInvoke>();

			if(!td.IsInterface)
			{
                foreach(IMethodDefinition methodDefinition in td.Methods)
				{
					if(methodDefinition.IsGeneric)
						continue;

					IRInvokeIdentity iiv = ProcessMethodInvokeIdentity(tt, methodDefinition, new List<IRVarName>());

					if(methodDefinition.IsStaticConstructor || (methodDefinition.IsStatic && methodDefinition.Name.Value.Equals("Main")))
						ProcessMethodDefinition(iiv, methodDefinition, loadinto, ldr);
					
					if(!methodDefinition.IsStatic)
					{
						ProcessMethodDefinition(iiv, methodDefinition, loadinto, ldr);
						declmethods.Add((IRVirtualInvoke)iiv.Sig);
					}
				}

				foreach(IMethodImplementation imi in td.ExplicitImplementationOverrides)
				{
					IRType ovt = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(imi.ImplementedMethod.ContainingType));

					string pmname = imi.ImplementedMethod.Name.Value;
					string fmname = imi.ImplementingMethod.Name.Value;

					/*
					ITypeReference imct = imi.ImplementedMethod.ContainingType.ResolvedType;
					string fmname = "";
					if(imct is IGenericTypeInstance)
					{
						IMethodDefinition umsd = ((ISpecializedMethodDefinition)imi.ImplementedMethod.ResolvedMethod).UnspecializedVersion;
						fmname = umsd.ContainingTypeDefinition.ResolvedType.InstanceType.ToString();

						int lops = imi.ImplementingMethod.Name.Value.LastIndexOf(".");
						fmname = fmname + imi.ImplementingMethod.Name.Value.Substring(lops);
					}
					else
						fmname = imi.ImplementingMethod.Name.Value;
					*/

					List<IRType> fsigl = new List<IRType>();
					List<IRType> psigl = new List<IRType>();
					foreach(IParameterTypeInformation ipl in imi.ImplementingMethod.Parameters)
					{
						IRType stt = s_loader.VisitType(ipl.Type);
						if(ipl.IsByReference)
							stt = s_irprog.TypeTable.InternReferenceTypeFor(stt);

						fsigl.Add(stt);
						psigl.Add(stt);
					}

					IRVirtualInvoke sigexplicit = s_irprog.InvokeTable.InternVirtualInvoke(fmname, fsigl);
					IRVirtualInvoke sigpartial = s_irprog.InvokeTable.InternVirtualInvoke(pmname, psigl);

					Contract.Assert(declmethods.Contains(sigexplicit), "That won't end well.");

					explicitoverridemap.Add(new Tuple<IRType, IRInvokeSig>(ovt, sigpartial), sigexplicit);
				}
			}
			tt.TypeDescription.LoadMemberImplInfo(declmethods, explicitoverridemap);
		}

		/// <summary>
		/// Given a single partially instantiated type, finish by processing the full type definition
		/// </summary>
		internal static void ProcessMethodDefinition(IRInvokeIdentity invid, IMethodDefinition md, IRProgram loadinto, CCILoader ldr)
		{
			s_irprog = loadinto;
			s_currentProcType = invid.DefInClass;
			s_loader = ldr;

			s_currpdb = s_loader.GetPDBForType(md.ContainingType);
			s_prevloc = new IRSourceLocation("DummyInitialLocation", -1, -1);

			//if((!tt.TypeDescription.IsBuiltinType) && (!(tt is IRPrimitiveType)))
			//Console.WriteLine("    Method: " + md.Name.Value);

			IRBodyDef bdf = ProcessMethodBody(invid.DefInClass, md);
			s_irprog.MethodBodyTable.InternNewBodyDef(bdf);
		}

		/// <summary>
		/// Extract the field tag info for a given member field
		/// </summary>
		private static SpecialFieldTag ExtractFieldTag(IFieldDefinition fieldDef)
		{
			Contract.Requires(fieldDef != null);

			bool cardr = fieldDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.CardinalityFieldAttribute"));
			bool collur = fieldDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.MultiLocationFieldAttribute"));

			bool enumr = fieldDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.EnumeratorCollectionFieldAttribute"));
			
			if(cardr)
				return SpecialFieldTag.ContainerCardField;
			else if(collur)
				return SpecialFieldTag.SummaryLocationField;
			else if(enumr)
				return SpecialFieldTag.EnumeratorCollectionField;
			else
				return SpecialFieldTag.NormalField;
		}

		/// <summary>
		/// Extract the field qualifier info for a given member field
		/// </summary>
		private static FieldQualifiers ExtractFieldQual(IFieldDefinition fieldDef)
		{
			Contract.Requires(fieldDef != null);

			FieldQualifiers fq;

			//first check for visibility state
			switch(fieldDef.Visibility)
			{
				case TypeMemberVisibility.Private:
					fq = FieldQualifiers.PrivateTag;
					break;
				case TypeMemberVisibility.Public:
					fq = FieldQualifiers.PublicTag;
					break;
				default:
					fq = FieldQualifiers.InternalTag;
					break;
			}

			return fq;
		}

		/// <summary>
		/// A helper for converting into locations for our IR.
		/// </summary>
		private static IRSourceLocation ConvertToIRLocation(IEnumerable<IPrimarySourceLocation> ipsl, int bytecodeoffset)
		{
			IPrimarySourceLocation[] ipsa = ipsl.ToArray();
			Array.Sort(ipsa, (IPrimarySourceLocation ipsl1, IPrimarySourceLocation ipsl2) => ipsl1.StartLine - ipsl2.StartLine);
			if(ipsa.Length == 0)
				return new IRSourceLocation(s_prevloc.FileName, s_prevloc.Line, bytecodeoffset);
			else
			{
				IRSourceLocation nsl = new IRSourceLocation(ipsa[0].PrimarySourceDocument.Location, ipsa[0].StartLine, bytecodeoffset);
				s_prevloc = nsl;
				return nsl;
			}
		}

		/// <summary>
		/// A helper for converting into locations for our IR.
		/// </summary>
		private static IRSourceLocation ConvertToIRLocation(IOperation op)
		{
			return ConvertToIRLocation(s_currpdb.GetPrimarySourceLocationsFor(op.Location), (int)op.Offset);
		}

		/// <summary>
		/// Convert the CCI method information into the IRInvokeIdentity for the method.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
		private static IRInvokeIdentity ProcessMethodInvokeIdentity(IRType declin, IMethodDefinition methodDefinition, List<IRVarName> namel)
		{
			IRType rtype = s_loader.VisitType(methodDefinition.Type);

			string fmname = methodDefinition.Name.Value;

			List<IRType> sigl = new List<IRType>();
			foreach(IParameterDefinition ipl in methodDefinition.Parameters)
			{
				IRType tt = s_loader.VisitType(ipl.Type);

				if(ipl.IsByReference)
					tt = s_irprog.TypeTable.InternReferenceTypeFor(tt);

				sigl.Add(tt);
				namel.Add(s_irprog.InternNewLocalVar(ipl.Name.Value));
			}

			IRInvokeSig sig;
			if(methodDefinition.IsStatic)
				sig = s_irprog.InvokeTable.InternStaticInvoke(declin, fmname, sigl);
			else
				sig = s_irprog.InvokeTable.InternVirtualInvoke(fmname, sigl);

			IRInvokeIdentity ii = s_irprog.InvokeTable.InternInvokeIdentity(declin, sig);

			return ii;
		}

		/// <summary>
		/// Convert the CCI bytecodes into our IR.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
		private static IRBodyDef ProcessMethodBody(IRType declin, IMethodDefinition methodDefinition)
		{
			Contract.Requires(declin != null);
			Contract.Requires(methodDefinition != null);

			IRType rtype = s_loader.VisitType(methodDefinition.Type);
			List<IRVarName> namel = new List<IRVarName>();
			IRInvokeIdentity ii = ProcessMethodInvokeIdentity(declin, methodDefinition, namel);
			s_currInvoke = ii;
			s_currMethod = methodDefinition;

			MethodQualifiers mq = ExtractMethodTagAndQual(methodDefinition);
			IRBodyDef bdf = null;

			if((mq & MethodQualifiers.BuiltinTag) != 0)
			{
				String biop = (String)((IMetadataConstant)FetchMethodAttributeIfPossible(methodDefinition, "CSharpLibs.Annotations.BuiltinSemanticsAttribute")).Value;

				List<IRStaticField> usedmodstatics = new List<IRStaticField>();
				IMetadataExpression usmde = FetchMethodAttributeIfPossible(methodDefinition, "CSharpLibs.Annotations.UsedModStaticsAttribute");
				if(usmde != null)
					ExtractAdditionalStatics(usmde, usedmodstatics);

				bdf = new IRBodyDef(ii, rtype, namel, mq, biop, usedmodstatics, ConvertToIRLocation(s_currpdb.GetPrimarySourceLocationsFor(methodDefinition.Locations), -1));
			}
			else if(methodDefinition.IsAbstract)
			{
				bdf = new IRBodyDef(ii, rtype, namel, mq, null, ConvertToIRLocation(s_currpdb.GetPrimarySourceLocationsFor(methodDefinition.Locations), -1));
			}
			else if(methodDefinition.IsExternal)
			{
				String biop;
				if(methodDefinition.ContainingTypeDefinition.IsDelegate)
				{
					if(methodDefinition.IsConstructor)
						biop = "delegate_cons";
					else
						biop = "delegate_invoke";
				}
				else
					biop = "UnknownExternalMethod: " + methodDefinition.Name.ToString();

				List<IRStaticField> usedmodstatics = new List<IRStaticField>();
				bdf = new IRBodyDef(ii, rtype, namel, mq | MethodQualifiers.BuiltinTag, biop, usedmodstatics, ConvertToIRLocation(s_currpdb.GetPrimarySourceLocationsFor(methodDefinition.Locations), -1));
			}
			else
			{
				IRBody bb = ExtractBody(methodDefinition.Body);
				bdf = new IRBodyDef(ii, rtype, namel, mq, bb, ConvertToIRLocation(s_currpdb.GetPrimarySourceLocationsFor(methodDefinition.Locations), -1));
			}

			return bdf; 
		}

		/// <summary>
		/// Extract the method tag and qualifier info for a given method, 
		/// </summary>
		private static MethodQualifiers ExtractMethodTagAndQual(IMethodDefinition methodDef)
		{
			Contract.Requires(methodDef != null);

			MethodQualifiers mq;

			//first check for visibility state
			switch(methodDef.Visibility)
			{
				case TypeMemberVisibility.Private:
					mq = MethodQualifiers.PrivateTag;
					break;
				case TypeMemberVisibility.Public:
					mq = MethodQualifiers.PublicTag;
					break;
				default:
					mq = MethodQualifiers.InternalTag;
					break;
			}

			if(methodDef.IsAbstract)
				mq = mq | MethodQualifiers.AbstractTag;

			bool builtin = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.BuiltinMethodAttribute"));
			bool typepatchneeded = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.TypePatchNeededAttribute"));
			
			bool enumadvance = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.EnumeratorAdvanceAttribute"));
			bool indexget = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.CollectionGetterIndexAttribute"));
			bool donotclear = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.DoNotClearCollectionPositionAttribute"));
			
			if(builtin)
				mq = mq | MethodQualifiers.BuiltinTag;

			if(typepatchneeded)
				mq = mq | MethodQualifiers.TypePatchNeeded;

			if(enumadvance)
				mq = mq | MethodQualifiers.AdvanceEnumerator;

			if(indexget)
				mq = mq | MethodQualifiers.GetIndexer;

			if(donotclear)
				mq = mq | MethodQualifiers.DoNotClearTraverse;

			bool enumgetcont = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.EnumeratorGetterSimpleContainerAttribute"));
			bool enumgetdict = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.EnumeratorGetterDictionaryAttribute"));
			bool enumgetdictk = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.EnumeratorGetterDictionaryKeysAttribute"));
			bool enumgetdictv = methodDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.EnumeratorGetterDictionaryValuesAttribute"));

			if(enumgetcont)
				mq = mq | MethodQualifiers.EnumeratorGetterSimpleContainer;

			if(enumgetdict)
				mq = mq | MethodQualifiers.EnumeratorGetterDictionary;

			if(enumgetdictk)
				mq = mq | MethodQualifiers.EnumeratorGetterDictionaryKeys;

			if(enumgetdictv)
				mq = mq | MethodQualifiers.EnumeratorGetterSimpleDictionaryValues;

			return mq;
		}

		/// <summary>
		/// Parse out the method body.
		/// </summary>
		private static IRBody ExtractBody(IMethodBody mbody)
		{
			List<IRBasicBlock> blcks = new List<IRBasicBlock>();
			ParseOutInstList(mbody, blcks);

			return new IRBody(blcks);
		}

		private static void PrintExtractStmtInfoDebug(String s)
		{
			//Console.WriteLine(s);
		}

		/// <summary>
		/// Constant target id for the return block
		/// </summary>
		public const uint RETURN_TARGET = 10241024;

		/// <summary>
		/// Extract a list of all the instructions in the body also fill in a map from offsets in the bytecode to indecies in the list.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1809:AvoidExcessiveLocals")]
		private static void ParseOutInstList(IMethodBody mbody, List<IRBasicBlock> blcks)
		{
			List<IOperation> operations = new List<IOperation>(mbody.Operations);
			int count = operations.Count;

			////
			//Record all offsets that appear as part of an exception handler

			Dictionary<uint, bool> offsetsUsedInExceptionInformation = new Dictionary<uint, bool>();
			foreach(var exceptionInfo in mbody.OperationExceptionInformation)
			{
				uint x = exceptionInfo.TryStartOffset;
				if(!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
				x = exceptionInfo.TryEndOffset;
				if(!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
				x = exceptionInfo.HandlerStartOffset;
				if(!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
				x = exceptionInfo.HandlerEndOffset;
				if(!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
				if(exceptionInfo.HandlerKind == HandlerKind.Filter)
				{
					x = exceptionInfo.FilterDecisionStartOffset;
					if(!offsetsUsedInExceptionInformation.ContainsKey(x)) offsetsUsedInExceptionInformation.Add(x, true);
				}
			}

			////
			//Pass 1: Make a label for each branch target and the exit

			uint lblctr = 1;
			Dictionary<uint, uint> offset2Label = new Dictionary<uint, uint>();
			Dictionary<uint, int> offset2index = new Dictionary<uint, int>();
			offset2Label.Add(0, 0);
			offset2Label.Add(RETURN_TARGET, RETURN_TARGET);
			for(int i = 0; i < count; i++)
			{
				IOperation op = operations[i];
				offset2index.Add(op.Offset, i);

				switch(op.OperationCode)
				{
					case OperationCode.Beq:
					case OperationCode.Bge:
					case OperationCode.Bge_Un:
					case OperationCode.Bgt:
					case OperationCode.Bgt_Un:
					case OperationCode.Ble:
					case OperationCode.Ble_Un:
					case OperationCode.Blt:
					case OperationCode.Blt_Un:
					case OperationCode.Bne_Un:
					case OperationCode.Brfalse:
					case OperationCode.Brtrue:
					case OperationCode.Beq_S:
					case OperationCode.Bge_S:
					case OperationCode.Bge_Un_S:
					case OperationCode.Bgt_S:
					case OperationCode.Bgt_Un_S:
					case OperationCode.Ble_S:
					case OperationCode.Ble_Un_S:
					case OperationCode.Blt_S:
					case OperationCode.Blt_Un_S:
					case OperationCode.Bne_Un_S:
					case OperationCode.Brfalse_S:
					case OperationCode.Brtrue_S:
						uint x = (uint)op.Value;
						if(!offset2Label.ContainsKey(x))
							offset2Label.Add(x, lblctr++);

						IOperation fallthroughtrgt = operations[i + 1];
						uint y = (uint)fallthroughtrgt.Offset;
						if(!offset2Label.ContainsKey(y))
							offset2Label.Add(y, lblctr++);
						break;
					case OperationCode.Br:
					case OperationCode.Br_S:
					case OperationCode.Leave:
					case OperationCode.Leave_S:
						uint z = (uint)op.Value;
						if(!offset2Label.ContainsKey(z))
							offset2Label.Add(z, lblctr++);
						break;
					case OperationCode.Switch:
						IOperation sfallthroughtrgt = operations[i + 1];
						uint sy = (uint)sfallthroughtrgt.Offset;
						if(!offset2Label.ContainsKey(sy))
							offset2Label.Add(sy, lblctr++);

						uint[] offsets = op.Value as uint[];
						foreach(var offset in offsets)
						{
							if(!offset2Label.ContainsKey(offset))
								offset2Label.Add(offset, lblctr++);
						}
						break;
					default:
						break;
				}
			}

			////
			//Emit each operation, along with labels

			//the simulation stack for us to track types on the stack
			Stack<IRType> execTransStack = new Stack<IRType>();

			//the basic block that we are currently producing
			IRBasicBlock currentBlock = null;

			//dictionary to keep track of our cross jump stack structure
			Dictionary<uint, List<IRType>> crossJumpVarMap = new Dictionary<uint, List<IRType>>();

			Dictionary<IRBasicBlock, HashSet<uint>> bbopcodeextent = new Dictionary<IRBasicBlock, HashSet<uint>>();

			HashSet<long> doneBlocks = new HashSet<long>();
			Queue<int> pendingOffsets = new Queue<int>();
			pendingOffsets.Enqueue(0);

			while(pendingOffsets.Count != 0)
			{
				int j = pendingOffsets.Dequeue();
				for(; ; ++j)
				{
					IOperation op = operations[j];

					//Mark operation if it is pointed to by an exception handler
					bool ignore;
					uint offset = op.Offset;
					bool isHandlerEntry = false;
					if(offsetsUsedInExceptionInformation.TryGetValue(offset, out ignore))
					{
						foreach(var exceptionInfo in mbody.OperationExceptionInformation)
						{
							//if(offset == exceptionInfo.TryStartOffset)
							//	Console.WriteLine("Enter Try");

							// Never need to do anthing when offset == exceptionInfo.TryEndOffset because
							// we pick up an EndTryBody from the HandlerEndOffset below
							//  generator.EndTryBody();

							if(offset == exceptionInfo.HandlerStartOffset)
							{
								switch(exceptionInfo.HandlerKind)
								{
									case HandlerKind.Catch:
									case HandlerKind.Fault:
									case HandlerKind.Filter:
									case HandlerKind.Finally:
										//Console.WriteLine("Enter a handler.");
										isHandlerEntry = true;
										break;
								}
							}
						}
					}

					//
					//This block is where all the magic happens, I am not thrilled with it.
					//
					if(offset2Label.ContainsKey(op.Offset) || isHandlerEntry)
					{
						if(currentBlock != null)
						{
							//add a jump if needed to the tail end of the block
							if(currentBlock.Operations.Count == 0 || (!currentBlock.Operations[currentBlock.Operations.Count - 1].IsStmtValidBlockEnd))
								currentBlock.Operations.Add(IRBranchOp.MakeBranchUOp(offset2Label[op.Offset], new IRSourceLocation("BlockExitJump", -1, -1)));

							blcks.Add(currentBlock);
							doneBlocks.Add(currentBlock.BlockID);

							List<uint> trgts = new List<uint>();
							currentBlock.GetAllBranchTargets(trgts);
							foreach(uint trgto in trgts)
							{
								GenStackToVarDump(trgto, crossJumpVarMap, execTransStack);
								uint toff = offset2Label.First((KeyValuePair<uint, uint> pvo) => pvo.Value == trgto).Key;

								if((!doneBlocks.Contains(trgto)) && (!pendingOffsets.Contains(offset2index[toff])))
									pendingOffsets.Enqueue(offset2index[toff]);
							}

							execTransStack.Clear();
							currentBlock = null;
							break;
						}

						currentBlock = new IRBasicBlock(new List<IRByteCode>(), offset2Label[op.Offset]);
						HashSet<uint> extentnew = new HashSet<uint>();
						extentnew.Add(op.Offset);
						bbopcodeextent.Add(currentBlock, extentnew);

						ReloadStackDumpAtEntry(offset2Label[op.Offset], crossJumpVarMap, execTransStack);
					}

					//mess with opcode offsets stuff
					bbopcodeextent[currentBlock].Add(op.Offset);

					//vars that are used as temps in multiple cases
					uint nextOpOff;
					IRType evalloc1;
					IRType evalloc2;
					IRType cctype;
					IRType ootype;

					IFieldDefinition fielddef;
					SpecialFieldTag sft;
					FieldQualifiers fqual;
					IRMemberField mmfield;
					IRReferenceType mmtyperef;
					IRStaticField ssfield;

					//Emit operation along with any injection
					switch(op.OperationCode)
					{
						case OperationCode.Constrained_:
							PrintExtractStmtInfoDebug("Constrain");
							IOperation nextop = operations[j + 1];
							ExtractConstrainOp(op, (ITypeReference)op.Value, (IMethodReference)nextop.Value, execTransStack, currentBlock);
							break;
						case OperationCode.No_:
						case OperationCode.Readonly_:
						case OperationCode.Tail_:
						case OperationCode.Unaligned_:
						case OperationCode.Volatile_:
							PrintExtractStmtInfoDebug("Prefix");
							break;
						case OperationCode.Add:
						case OperationCode.Add_Ovf:
							PrintExtractStmtInfoDebug("Add");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(evalloc1));
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Add, ConvertToIRLocation(op)));
							break;
						case OperationCode.Add_Ovf_Un:
							PrintExtractStmtInfoDebug("AddU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(evalloc1));
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.AddU, ConvertToIRLocation(op)));
							break;
						case OperationCode.And:
							PrintExtractStmtInfoDebug("And");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.And, ConvertToIRLocation(op)));
							break;
						case OperationCode.Arglist:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Beq:
						case OperationCode.Beq_S:
							PrintExtractStmtInfoDebug("Branch EQ");
							evalloc1 = execTransStack.Peek();
							if(evalloc1 is IRPtrType || evalloc1 is IRReferenceType)
							{
								execTransStack.Pop();
								execTransStack.Pop();

								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.DerefableEQ, ConvertToIRLocation(op)));
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							}
							else
							{
								execTransStack.Pop();
								evalloc2 = execTransStack.Pop();
								Contract.Assert(evalloc1 == evalloc2);
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.PrimEQ, ConvertToIRLocation(op)));
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							}
							break;
						case OperationCode.Bge:
						case OperationCode.Bge_S:
							PrintExtractStmtInfoDebug("Branch GE");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.GreaterEQ, ConvertToIRLocation(op)));
							nextOpOff = operations[j + 1].Offset;
							currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							break;
						case OperationCode.Bge_Un:
						case OperationCode.Bge_Un_S:
							PrintExtractStmtInfoDebug("Branch GEU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.GreaterEQU, ConvertToIRLocation(op)));
							nextOpOff = operations[j + 1].Offset;
							currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							break;
						case OperationCode.Bgt:
						case OperationCode.Bgt_S:
							PrintExtractStmtInfoDebug("Branch GT");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Greater, ConvertToIRLocation(op)));
							nextOpOff = operations[j + 1].Offset;
							currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							break;
						case OperationCode.Bgt_Un:
						case OperationCode.Bgt_Un_S:
							PrintExtractStmtInfoDebug("Branch GTU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							if(evalloc2 is IRPtrType || evalloc2 is IRReferenceType)
							{
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Pop, ConvertToIRLocation(op)));
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.NonNull, ConvertToIRLocation(op)));
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							}
							else
							{
								Contract.Assert(evalloc1 == evalloc2);
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.GreaterU, ConvertToIRLocation(op)));
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							}
							break;
						case OperationCode.Ble:
						case OperationCode.Ble_S:
							PrintExtractStmtInfoDebug("Branch LE");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.LessEQ, ConvertToIRLocation(op)));
							nextOpOff = operations[j + 1].Offset;
							currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							break;
						case OperationCode.Ble_Un:
						case OperationCode.Ble_Un_S:
							PrintExtractStmtInfoDebug("Branch LEU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.LessEQU, ConvertToIRLocation(op)));
							nextOpOff = operations[j + 1].Offset;
							currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							break;
						case OperationCode.Blt:
						case OperationCode.Blt_S:
							PrintExtractStmtInfoDebug("Branch LT");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Less, ConvertToIRLocation(op)));
							nextOpOff = operations[j + 1].Offset;
							currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							break;
						case OperationCode.Blt_Un:
						case OperationCode.Blt_Un_S:
							PrintExtractStmtInfoDebug("Branch LT");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.LessU, ConvertToIRLocation(op)));
							nextOpOff = operations[j + 1].Offset;
							currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							break;
						case OperationCode.Bne_Un:
						case OperationCode.Bne_Un_S:
							PrintExtractStmtInfoDebug("Branch NEQ");
							evalloc1 = execTransStack.Peek();
							if(evalloc1 is IRPtrType || evalloc1 is IRReferenceType)
							{
								execTransStack.Pop();
								execTransStack.Pop();

								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.DerefableEQ, ConvertToIRLocation(op)));
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[nextOpOff], offset2Label[(uint)op.Value], ConvertToIRLocation(op)));
							}
							else
							{
								execTransStack.Pop();
								evalloc2 = execTransStack.Pop();
								Contract.Assert(evalloc1 == evalloc2);
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.PrimEQ, ConvertToIRLocation(op)));
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[nextOpOff], offset2Label[(uint)op.Value], ConvertToIRLocation(op)));
							}
							break;
						case OperationCode.Br:
						case OperationCode.Br_S:
							PrintExtractStmtInfoDebug("Branch");
							currentBlock.Operations.Add(IRBranchOp.MakeBranchUOp(offset2Label[(uint)op.Value], ConvertToIRLocation(op)));
							break;
						case OperationCode.Brfalse:
						case OperationCode.Brfalse_S:
							PrintExtractStmtInfoDebug("Branch False");
							evalloc1 = execTransStack.Peek();
							if(evalloc1 is IRPtrType || evalloc1 is IRReferenceType)
							{
								execTransStack.Pop();
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.NonNull, ConvertToIRLocation(op)));
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[nextOpOff], offset2Label[(uint)op.Value], ConvertToIRLocation(op)));
							}
							else
							{
								execTransStack.Pop();
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[nextOpOff], offset2Label[(uint)op.Value], ConvertToIRLocation(op)));
							}
							break;
						case OperationCode.Brtrue:
						case OperationCode.Brtrue_S:
							PrintExtractStmtInfoDebug("Branch True");
							evalloc1 = execTransStack.Peek();
							if(evalloc1 is IRPtrType || evalloc1 is IRReferenceType)
							{
								execTransStack.Pop();
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.NonNull, ConvertToIRLocation(op)));
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							}
							else
							{
								execTransStack.Pop();
								nextOpOff = operations[j + 1].Offset;
								currentBlock.Operations.Add(IRBranchOp.MakeBranchCOp(offset2Label[(uint)op.Value], offset2Label[nextOpOff], ConvertToIRLocation(op)));
							}
							break;
						case OperationCode.Call:
							PrintExtractStmtInfoDebug("Call");
							ExtractCallOp(op, (IMethodReference)op.Value, true, execTransStack, currentBlock);
							break;
						case OperationCode.Calli:
							PrintExtractStmtInfoDebug("Call-i");
							throw new NotImplementedException("Need to figure out what op.Value is and do translation similar to ExtractCallOp above.");
						case OperationCode.Ceq:
							PrintExtractStmtInfoDebug("CEQ");
							evalloc1 = execTransStack.Peek();
							if(evalloc1 is IRPtrType || evalloc1 is IRReferenceType)
							{
								execTransStack.Pop();
								execTransStack.Pop();

								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.DerefableEQ, ConvertToIRLocation(op)));
								execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							}
							else
							{
								execTransStack.Pop();
								evalloc2 = execTransStack.Pop();
								Contract.Assert(evalloc1 == evalloc2);
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.PrimEQ, ConvertToIRLocation(op)));
								execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							}
							break;
						case OperationCode.Cgt:
							PrintExtractStmtInfoDebug("CGT");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Greater, ConvertToIRLocation(op)));
							break;
						case OperationCode.Cgt_Un:
							PrintExtractStmtInfoDebug("CGTU");
							evalloc1 = execTransStack.Peek();
							if(evalloc1 is IRPtrType || evalloc1 is IRReferenceType)
							{
								execTransStack.Pop();
								execTransStack.Pop();

								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Pop, ConvertToIRLocation(op)));
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.NonNull, ConvertToIRLocation(op)));
								execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							}
							else
							{
								execTransStack.Pop();
								evalloc2 = execTransStack.Pop();
								Contract.Assert(evalloc1 == evalloc2);
								currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.GreaterU, ConvertToIRLocation(op)));
								execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							}
							break;
						case OperationCode.Ckfinite:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Clt:
							PrintExtractStmtInfoDebug("CLT");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Less, ConvertToIRLocation(op)));
							break;
						case OperationCode.Clt_Un:
							PrintExtractStmtInfoDebug("CLTU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.LessU, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_I:
						case OperationCode.Conv_Ovf_I:
						case OperationCode.Conv_Ovf_I_Un:
						case OperationCode.Conv_U:
						case OperationCode.Conv_Ovf_U:
						case OperationCode.Conv_Ovf_U_Un:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Conv_I1:
						case OperationCode.Conv_Ovf_I1:
						case OperationCode.Conv_Ovf_I1_Un:
							PrintExtractStmtInfoDebug("Conv to int8");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.Int8Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_U1:
						case OperationCode.Conv_Ovf_U1:
						case OperationCode.Conv_Ovf_U1_Un:
							PrintExtractStmtInfoDebug("Conv to uint8");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.UInt64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.UInt8Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_I2:
						case OperationCode.Conv_Ovf_I2:
						case OperationCode.Conv_Ovf_I2_Un:
							PrintExtractStmtInfoDebug("Conv to int16");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.Int16Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_U2:
						case OperationCode.Conv_Ovf_U2:
						case OperationCode.Conv_Ovf_U2_Un:
							PrintExtractStmtInfoDebug("Conv to uint16");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.UInt64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.UInt16Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_I4:
						case OperationCode.Conv_Ovf_I4:
						case OperationCode.Conv_Ovf_I4_Un:
							PrintExtractStmtInfoDebug("Conv to int32");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.Int32Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_U4:
						case OperationCode.Conv_Ovf_U4:
						case OperationCode.Conv_Ovf_U4_Un:
							PrintExtractStmtInfoDebug("Conv to uint32");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.UInt64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.UInt32Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_I8:
						case OperationCode.Conv_Ovf_I8:
						case OperationCode.Conv_Ovf_I8_Un:
							PrintExtractStmtInfoDebug("Conv to int64");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.Int64Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_U8:
						case OperationCode.Conv_Ovf_U8:
						case OperationCode.Conv_Ovf_U8_Un:
							PrintExtractStmtInfoDebug("Conv to uint64");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.UInt64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.UInt64Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_R_Un:
						case OperationCode.Conv_R4:
							PrintExtractStmtInfoDebug("Conv to Float");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Float64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.Float32Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Conv_R8:
							PrintExtractStmtInfoDebug("Conv to Double");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Float64Type));
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Conv, s_irprog.TypeTable.Float64Type, -1, ConvertToIRLocation(op)));
							break;
						case OperationCode.Cpblk:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Div:
							PrintExtractStmtInfoDebug("DIV");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Div, ConvertToIRLocation(op)));
							break;
						case OperationCode.Div_Un:
							PrintExtractStmtInfoDebug("DIVU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.DivU, ConvertToIRLocation(op)));
							break;
						case OperationCode.Dup:
							PrintExtractStmtInfoDebug("DUP");
							cctype = execTransStack.Peek();
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Dup, ConvertToIRLocation(op)));
							execTransStack.Push(cctype);
							break;
						case OperationCode.Initblk:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Ldarg:
						case OperationCode.Ldarg_0:
						case OperationCode.Ldarg_1:
						case OperationCode.Ldarg_2:
						case OperationCode.Ldarg_3:
						case OperationCode.Ldarg_S:
							PrintExtractStmtInfoDebug("Load Arg");
							GenLoadArgOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldarga:
						case OperationCode.Ldarga_S:
							PrintExtractStmtInfoDebug("Load Arg Address");
							GenLoadArgAddressOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldc_I4:
						case OperationCode.Ldc_I4_0:
						case OperationCode.Ldc_I4_1:
						case OperationCode.Ldc_I4_2:
						case OperationCode.Ldc_I4_3:
						case OperationCode.Ldc_I4_4:
						case OperationCode.Ldc_I4_5:
						case OperationCode.Ldc_I4_6:
						case OperationCode.Ldc_I4_7:
						case OperationCode.Ldc_I4_8:
						case OperationCode.Ldc_I4_M1:
						case OperationCode.Ldc_I4_S:
						case OperationCode.Ldc_I8:
							PrintExtractStmtInfoDebug("Load Int Const");
							GenLoadConstIntOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldc_R4:
						case OperationCode.Ldc_R8:
							PrintExtractStmtInfoDebug("Load Float Const");
							GenLoadConstFloatOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldftn:
							PrintExtractStmtInfoDebug("Load Function");
							GenLoadStaticFunctionOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldind_I:
						case OperationCode.Ldind_I1:
						case OperationCode.Ldind_I2:
						case OperationCode.Ldind_I4:
						case OperationCode.Ldind_I8:
						case OperationCode.Ldind_U1:
						case OperationCode.Ldind_U2:
						case OperationCode.Ldind_U4:
						case OperationCode.Ldind_R4:
						case OperationCode.Ldind_R8:
						case OperationCode.Ldind_Ref:
							PrintExtractStmtInfoDebug("Load Indirect");
							GenLoadIndirectOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldloc:
						case OperationCode.Ldloc_0:
						case OperationCode.Ldloc_1:
						case OperationCode.Ldloc_2:
						case OperationCode.Ldloc_3:
						case OperationCode.Ldloc_S:
							PrintExtractStmtInfoDebug("Load Local Var");
							GenLoadLocalOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldloca:
						case OperationCode.Ldloca_S:
							PrintExtractStmtInfoDebug("Load Local Var Address");
							GenLoadLocalAddressOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldnull:
							PrintExtractStmtInfoDebug("Load Null Constant");
							currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeLoadNullOperation(s_irprog.TypeTable.NullType, ConvertToIRLocation(op)));
							execTransStack.Push(s_irprog.TypeTable.NullType);
							break;
						case OperationCode.Leave:
						case OperationCode.Leave_S:
							PrintExtractStmtInfoDebug("Leave");
							nextOpOff = operations[j + 1].Offset;
							currentBlock.Operations.Add(IRBranchOp.MakeBranchUOp(offset2Label[(uint)op.Value], ConvertToIRLocation(op)));
							execTransStack.Clear();
							break;
						case OperationCode.Localloc:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Mul:
						case OperationCode.Mul_Ovf:
								PrintExtractStmtInfoDebug("MUL");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Mult, ConvertToIRLocation(op)));
							break;
						case OperationCode.Mul_Ovf_Un:
							PrintExtractStmtInfoDebug("MULU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.MultU, ConvertToIRLocation(op)));
							break;
						case OperationCode.Neg:
							PrintExtractStmtInfoDebug("NEG");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Neg, ConvertToIRLocation(op)));
							break;
						case OperationCode.Nop:
							PrintExtractStmtInfoDebug("NOP");
							break;
						case OperationCode.Not:
							PrintExtractStmtInfoDebug("NOT");
							evalloc1 = execTransStack.Pop();
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Not, ConvertToIRLocation(op)));
							break;
						case OperationCode.Or:
							PrintExtractStmtInfoDebug("OR");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Or, ConvertToIRLocation(op)));
							break;
						case OperationCode.Pop:
							PrintExtractStmtInfoDebug("Pop");
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Pop, ConvertToIRLocation(op)));
							execTransStack.Pop();
							break;
						case OperationCode.Rem:
							PrintExtractStmtInfoDebug("REM");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Rem, ConvertToIRLocation(op)));
							break;
						case OperationCode.Rem_Un:
							PrintExtractStmtInfoDebug("REMU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.RemU, ConvertToIRLocation(op)));
							break;
						case OperationCode.Ret:
							PrintExtractStmtInfoDebug("Return");
							Contract.Assert(execTransStack.Count <= 1, "Either a single return value or empty on exit");

							currentBlock.Operations.Add(IRBranchOp.MakeBranchUOp(offset2Label[RETURN_TARGET], ConvertToIRLocation(op)));
							blcks.Add(currentBlock);
							doneBlocks.Add(currentBlock.BlockID);
							execTransStack.Clear();
							currentBlock = null;
							break;
						case OperationCode.Shl:
							PrintExtractStmtInfoDebug("SHL");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							execTransStack.Push(evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Shl, ConvertToIRLocation(op)));
							break;
						case OperationCode.Shr:
							PrintExtractStmtInfoDebug("SHR");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							execTransStack.Push(evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Shr, ConvertToIRLocation(op)));
							break;
						case OperationCode.Shr_Un:
							PrintExtractStmtInfoDebug("SHRU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							execTransStack.Push(evalloc2);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.ShrU, ConvertToIRLocation(op)));
							break;
						case OperationCode.Starg:
						case OperationCode.Starg_S:
							PrintExtractStmtInfoDebug("Store Arg");
							GenStoreArgOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Stind_I:
						case OperationCode.Stind_I1:
						case OperationCode.Stind_I2:
						case OperationCode.Stind_I4:
						case OperationCode.Stind_I8:
						case OperationCode.Stind_R4:
						case OperationCode.Stind_R8:
						case OperationCode.Stind_Ref:
							PrintExtractStmtInfoDebug("Store Indirect");
							GenStoreIndirectOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Stloc:
						case OperationCode.Stloc_0:
						case OperationCode.Stloc_1:
						case OperationCode.Stloc_2:
						case OperationCode.Stloc_3:
						case OperationCode.Stloc_S:
							PrintExtractStmtInfoDebug("Store Loc");
							GenStoreLocalOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Sub:
						case OperationCode.Sub_Ovf:
							PrintExtractStmtInfoDebug("SUB");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Sub, ConvertToIRLocation(op)));
							break;
						case OperationCode.Sub_Ovf_Un:
							PrintExtractStmtInfoDebug("SUBU");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.SubU, ConvertToIRLocation(op)));
							break;
						case OperationCode.Switch:
							PrintExtractStmtInfoDebug("Switch");
							uint[] offsets = op.Value as uint[];
							List<uint> trgts = new List<uint>();
							foreach(uint swi in offsets)
								trgts.Add(offset2Label[swi]);

							execTransStack.Pop();
							currentBlock.Operations.Add(IRBranchOp.MakeSwitchOp(trgts.ToArray(), ConvertToIRLocation(op)));
							break;
						case OperationCode.Xor:
							PrintExtractStmtInfoDebug("XOR");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							Contract.Assert(evalloc1 == evalloc2);
							execTransStack.Push(evalloc1);
							currentBlock.Operations.Add(new IREvalStackOp(OpCode.Op.Xor, ConvertToIRLocation(op)));
							break;
						case OperationCode.Box:
							PrintExtractStmtInfoDebug("Box");
							execTransStack.Pop();
							cctype = s_loader.VisitType((ITypeReference)op.Value);
							if(cctype is IRValueType)
							{
								currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Box, cctype, -1, ConvertToIRLocation(op)));
								ootype = s_irprog.TypeTable.InternBoxedTypeFor((IRValueType)cctype);
								ootype = s_irprog.TypeTable.InternPointerTypeFor(ootype);
								execTransStack.Push(ootype);
							}
							else
								execTransStack.Push(cctype); //nop if not a value type
							break;
						case OperationCode.Callvirt:
							PrintExtractStmtInfoDebug("Call Virt");
							ExtractCallOp(op, (IMethodReference)op.Value, false, execTransStack, currentBlock);
							break;
						case OperationCode.Castclass:
							PrintExtractStmtInfoDebug("Cast Class");
							execTransStack.Pop();
							cctype = (IRType)s_loader.VisitType((ITypeReference)op.Value);
							if(cctype is IRPtrType)
							{
								ootype = cctype;
							}
							else
							{
								ootype = s_irprog.TypeTable.InternBoxedTypeFor((IRValueType)cctype);
								ootype = s_irprog.TypeTable.InternPointerTypeFor(ootype);
							}

							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Cast, cctype, -1, ConvertToIRLocation(op)));
							execTransStack.Push(ootype);
							break;
						case OperationCode.Cpobj:
							PrintExtractStmtInfoDebug("Copy Mem");
							evalloc1 = execTransStack.Pop();
							evalloc2 = execTransStack.Pop();
							cctype = (IRType)s_loader.VisitType((ITypeReference)op.Value);

							Contract.Assert(evalloc1 is IRReferenceType && evalloc2 is IRReferenceType);
							Contract.Assert(((IRReferenceType)evalloc1).ReferenceTargetType == cctype && ((IRReferenceType)evalloc2).ReferenceTargetType == cctype);

							currentBlock.Operations.Add(IRLoadToEvalStackIndirect.MakeLoadIndirectOperation((IRReferenceType)evalloc1, ConvertToIRLocation(op)));
							currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeStoreIndirectOperation((IRReferenceType)evalloc2, ConvertToIRLocation(op)));
							break;
						case OperationCode.Initobj:
							evalloc1 = execTransStack.Pop();
							cctype = (IRType)s_loader.VisitType((ITypeReference)op.Value);
							Contract.Assert(evalloc1 is IRReferenceType && ((IRReferenceType)evalloc1).ReferenceTargetType == cctype);

							if(cctype is IRSignedIntegerType)
							{
								currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeLoadConstOperation(IRLiteralExp.MakeSignedIntegralLiteral(s_irprog.TypeTable.Int64Type, 0), ConvertToIRLocation(op)));
								currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeStoreIndirectOperation((IRReferenceType)evalloc1, ConvertToIRLocation(op)));
							}
							else if(cctype is IRUnSignedIntegerType)
							{
								currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeLoadConstOperation(IRLiteralExp.MakeSignedIntegralLiteral(s_irprog.TypeTable.Int64Type, 0), ConvertToIRLocation(op)));
								currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeStoreIndirectOperation((IRReferenceType)evalloc1, ConvertToIRLocation(op)));
							}
							else if(cctype is IRFloatingPointType)
							{
								currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeLoadConstOperation(IRLiteralExp.MakeFloatLiteral(s_irprog.TypeTable.Float64Type, 0.0), ConvertToIRLocation(op)));
								currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeStoreIndirectOperation((IRReferenceType)evalloc1, ConvertToIRLocation(op)));
							}
							else if(cctype is IRPtrType)
							{
								currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeLoadNullOperation(s_irprog.TypeTable.NullType, ConvertToIRLocation(op)));
								currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeStoreIndirectOperation((IRReferenceType)evalloc1, ConvertToIRLocation(op)));
							}
							else
							{
								currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeIndirectInitOperation((IRReferenceType)evalloc1, ConvertToIRLocation(op)));
							}
							break;
						case OperationCode.Isinst:
							PrintExtractStmtInfoDebug("IsInst");
							execTransStack.Pop();
							cctype = s_loader.VisitType((ITypeReference)op.Value);
							if(cctype is IRPtrType)
							{
								ootype = cctype;
							}
							else
							{
								ootype = s_irprog.TypeTable.InternBoxedTypeFor((IRValueType)cctype);
								ootype = s_irprog.TypeTable.InternPointerTypeFor(ootype);
							}
							currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.IsInst, ootype, -1, ConvertToIRLocation(op)));
							execTransStack.Push(ootype);
							break;
						case OperationCode.Ldelem:
						case OperationCode.Ldelem_I:
						case OperationCode.Ldelem_I1:
						case OperationCode.Ldelem_I2:
						case OperationCode.Ldelem_I4:
						case OperationCode.Ldelem_I8:
						case OperationCode.Ldelem_R4:
						case OperationCode.Ldelem_R8:
						case OperationCode.Ldelem_Ref:
						case OperationCode.Ldelem_U1:
						case OperationCode.Ldelem_U2:
						case OperationCode.Ldelem_U4:
							PrintExtractStmtInfoDebug("Load Elem Array");
							GenLoadArrayOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldelema:
							execTransStack.Pop();
							evalloc1 = ((IRPtrType)execTransStack.Pop()).PtrTargetType;
							cctype = s_loader.VisitType((ITypeReference)op.Value);
							Contract.Assert((evalloc1 is IRContainerType) && ((IRContainerType)evalloc1).IsArrayContainer, "bad operation");
							Contract.Assert(((IRContainerType)evalloc1).ContainerContentsType == cctype, "should match exactly");

							currentBlock.Operations.Add(IRPointerIndexOp.MakeArrayAddrIndex((IRContainerType)evalloc1, 1, ConvertToIRLocation(op)));
							execTransStack.Push(s_irprog.TypeTable.InternReferenceTypeFor(cctype));
							break;
						case OperationCode.Ldfld:
							PrintExtractStmtInfoDebug("Load Field");
							cctype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(((IFieldReference)op.Value).ContainingType));
							ootype = s_loader.VisitType(((IFieldReference)op.Value).Type);
							fielddef = ((IFieldReference)op.Value).ResolvedField;
							sft = ExtractFieldTag(fielddef);
							fqual = ExtractFieldQual(fielddef);
							mmfield = s_irprog.FullyInternMemberField(cctype, ((IFieldReference)op.Value).Name.Value, ootype, sft, fqual);
							mmtyperef = s_irprog.TypeTable.InternReferenceTypeFor(mmfield.FieldType);

							if(execTransStack.Peek() is IRStructType)
							{
								execTransStack.Pop();
								currentBlock.Operations.Add(IRLoadToEvalStackIndirect.MakeLoadStructFieldOperation(mmfield, ConvertToIRLocation(op)));
								execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(mmfield.FieldType));
							}
							else
							{
								execTransStack.Pop();
								currentBlock.Operations.Add(IRLoadToEvalStackIndirect.MakeLoadClassFieldOperation(mmfield, ConvertToIRLocation(op)));
								execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(mmfield.FieldType));
							}
							break;
						case OperationCode.Ldflda:
							PrintExtractStmtInfoDebug("Load Field Addr");
							cctype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(((IFieldReference)op.Value).ContainingType));
							ootype = s_loader.VisitType(((IFieldReference)op.Value).Type);
							fielddef = ((IFieldReference)op.Value).ResolvedField;
							sft = ExtractFieldTag(fielddef);
							fqual = ExtractFieldQual(fielddef);
							mmfield = s_irprog.FullyInternMemberField(cctype, ((IFieldReference)op.Value).Name.Value, ootype, sft, fqual);
							execTransStack.Pop();

							currentBlock.Operations.Add(IRPointerIndexOp.MakeFieldAddrIndex(mmfield, 0, ConvertToIRLocation(op)));
							execTransStack.Push(s_irprog.TypeTable.InternReferenceTypeFor(ootype));
							break;
						case OperationCode.Ldlen:
							PrintExtractStmtInfoDebug("Load Len");
							GenArrayLengthOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldobj:
							PrintExtractStmtInfoDebug("Load Obj");
							GenLoadIndirectOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Ldsfld:
							PrintExtractStmtInfoDebug("Load Static");
							cctype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(((IFieldReference)op.Value).ContainingType));
							ootype = s_loader.VisitType(((IFieldReference)op.Value).Type);
							ssfield = s_irprog.InternNewStaticFieldFull(cctype, ((IFieldReference)op.Value).Name.Value, ootype);

							currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeStaticFieldLoadOperation(ssfield, ConvertToIRLocation(op)));
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(ootype));
							break;
						case OperationCode.Ldsflda:
							PrintExtractStmtInfoDebug("Load Static Addr");
							cctype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(((IFieldReference)op.Value).ContainingType));
							ootype = s_loader.VisitType(((IFieldReference)op.Value).Type);
							ssfield = s_irprog.InternNewStaticFieldFull(cctype, ((IFieldReference)op.Value).Name.Value, ootype);

							currentBlock.Operations.Add(IRPointerIndexOp.MakeLoadGlobalAddr(ssfield, ConvertToIRLocation(op)));
							execTransStack.Push(s_irprog.TypeTable.InternPointerTypeFor(ootype));
							break;
						case OperationCode.Ldstr:
							PrintExtractStmtInfoDebug("Load String");
							currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeLoadStringOperation((String)op.Value, s_irprog.TypeTable.LookupPointerTypeFor(s_irprog.TypeTable.StringObjectType), ConvertToIRLocation(op)));
							ootype = s_irprog.TypeTable.InternPointerTypeFor(s_irprog.TypeTable.StringObjectType);
							execTransStack.Push(ootype);
							break;
						case OperationCode.Ldtoken:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Ldvirtftn:
							throw new NotImplementedException("Not Implemented Yet Opcode: " + op.OperationCode.ToString());
						case OperationCode.Mkrefany:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Newarr:
							PrintExtractStmtInfoDebug("Alloc Array");
							ootype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType((ITypeReference)op.Value));
							evalloc1 = execTransStack.Pop();
							Contract.Assert(evalloc1 is IRNumericType, "non-int type??");
							currentBlock.Operations.Add(new IRAllocationOp((IRContainerType)ootype, ConvertToIRLocation(op)));
							execTransStack.Push(ootype);
							break;
						case OperationCode.Newobj:
							PrintExtractStmtInfoDebug("Alloc Obj");
							GenObjAllocOp(op, execTransStack, currentBlock);
							break;
						case OperationCode.Refanytype:
						case OperationCode.Refanyval:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Rethrow:
							throw new NotImplementedException("Not Implemented Yet Opcode: " + op.OperationCode.ToString());
						case OperationCode.Sizeof:
							throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
						case OperationCode.Stelem:
						case OperationCode.Stelem_I:
						case OperationCode.Stelem_I1:
						case OperationCode.Stelem_I2:
						case OperationCode.Stelem_I4:
						case OperationCode.Stelem_I8:
						case OperationCode.Stelem_R4:
						case OperationCode.Stelem_R8:
						case OperationCode.Stelem_Ref:
							PrintExtractStmtInfoDebug("Store Elem");
							GenStoreArrayOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Stfld:
							PrintExtractStmtInfoDebug("Store Field");
							cctype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(((IFieldReference)op.Value).ContainingType));
							ootype = s_loader.VisitType(((IFieldReference)op.Value).Type);
							fielddef = ((IFieldReference)op.Value).ResolvedField;
							sft = ExtractFieldTag(fielddef);
							fqual = ExtractFieldQual(fielddef);
							mmfield = s_irprog.FullyInternMemberField(cctype, ((IFieldReference)op.Value).Name.Value, ootype, sft, fqual);
							mmtyperef = s_irprog.TypeTable.InternReferenceTypeFor(mmfield.FieldType);

							evalloc1 = execTransStack.Pop();
							execTransStack.Pop();

							currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeStoreFieldOperation(mmfield, ConvertToIRLocation(op)));
							break;
						case OperationCode.Stobj:
							PrintExtractStmtInfoDebug("Store Object");
							GenStoreIndirectOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Stsfld:
							PrintExtractStmtInfoDebug("Store Static");
							cctype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(((IFieldReference)op.Value).ContainingType));
							ootype = s_loader.VisitType(((IFieldReference)op.Value).Type);
							ssfield = s_irprog.InternNewStaticFieldFull(cctype, ((IFieldReference)op.Value).Name.Value, ootype);

							evalloc1 = execTransStack.Pop();
							currentBlock.Operations.Add(IRStoreFromEvalStackBasic.MakeStaticFieldStoreOperation(ssfield, ConvertToIRLocation(op)));
							break;
						case OperationCode.Throw:
							PrintExtractStmtInfoDebug("Throw");
							currentBlock.Operations.Add(IRBranchOp.MakeThrowOp(ConvertToIRLocation(op)));

							currentBlock.Operations.Add(IRBranchOp.MakeBranchUOp(offset2Label[RETURN_TARGET], ConvertToIRLocation(op)));
							blcks.Add(currentBlock);
							doneBlocks.Add(currentBlock.BlockID);
							execTransStack.Clear();
							currentBlock = null;

							break;
						case OperationCode.Unbox:
							PrintExtractStmtInfoDebug("Unbox");
							GenUnBoxOperation(op, execTransStack, currentBlock);
							break;
						case OperationCode.Unbox_Any:
							cctype = s_loader.VisitType((ITypeReference)op.Value);
							execTransStack.Pop();
							execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(cctype));
							if(cctype is IRValueType)
							{
								mmtyperef = s_irprog.TypeTable.InternReferenceTypeFor(cctype);
								currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.UnBox, cctype, -1, ConvertToIRLocation(op)));
								currentBlock.Operations.Add(IRLoadToEvalStackIndirect.MakeLoadIndirectOperation(mmtyperef, ConvertToIRLocation(op)));
							}
							else
								currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Cast, cctype, -1, ConvertToIRLocation(op)));
							break;
						default:
							throw new ArgumentException("Unknown Stmt Opcode: " + op.OperationCode.ToString());
					}

					if(op.OperationCode == OperationCode.Ret || op.OperationCode == OperationCode.Throw)
						break;
				}
			}

			//Add the return block
			IRBranchOp rets = IRBranchOp.MakeReturnOp(new IRSourceLocation("DummyReturnLocation", -1, -1));
			IRBasicBlock fbb = new IRBasicBlock(new List<IRByteCode>(), RETURN_TARGET);
			fbb.AddByteCodeAtEndOfBlock(rets);
			blcks.Add(fbb);

			////
			//Compute all the live variable scope information.
			List<IRVarExp> paramVars = new List<IRVarExp>();

			if(!s_currMethod.IsStatic)
			{
				IRVarName tvn = s_irprog.InternNewLocalVar("this");
				IRVarExp tpve;
				if(s_currInvoke.DefInClass is IRValueType)
					tpve = new IRVarExp(s_irprog.TypeTable.InternReferenceTypeFor(s_currentProcType), tvn);
				else
					tpve = new IRVarExp(s_irprog.TypeTable.InternPointerTypeFor((IRClassType)s_currentProcType), tvn);

				paramVars.Add(tpve);
			}

			foreach(IParameterDefinition pd in s_currMethod.Parameters)
			{
				IRType tt = s_loader.VisitType(pd.Type);

				if(pd.IsByReference)
					tt = s_irprog.TypeTable.InternReferenceTypeFor(tt);

				String vname = pd.Name.Value;
				IRVarName vn = s_irprog.InternNewLocalVar(vname);
				IRVarExp pve = new IRVarExp(tt, vn);
				paramVars.Add(pve);
			}

			List<ILocalScope> lscps = new List<ILocalScope>();
			lscps.AddRange(s_currpdb.GetLocalScopes(mbody));

			foreach(IRBasicBlock bb in blcks)
			{
				List<IRVarName> bbscp = new List<IRVarName>();
				Dictionary<IRVarName, IRType> bbtyinfo = new Dictionary<IRVarName, IRType>();

				foreach(IRVarExp pv in paramVars)
				{
					bbscp.Add(pv.Name);
					bbtyinfo.Add(pv.Name, pv.VarType);
				}

				if(bb.BlockID != RETURN_TARGET)
				{
					foreach(ILocalScope scp in lscps)
					{
						HashSet<uint> bbextent = bbopcodeextent[bb];
						bool overlap = false;
						for(uint i = scp.Offset; i <= scp.Offset + scp.Length; ++i)
							overlap |= bbextent.Contains(i);
						
						if(overlap)
						{
							foreach(ILocalDefinition lvd in s_currpdb.GetVariablesInScope(scp))
							{
								bool compilergen;
								String lvns = s_currpdb.GetSourceNameFor(lvd, out compilergen);
								IRVarName lvnn = s_irprog.InternNewLocalVar(lvns);
								bbscp.Add(lvnn);

								IRType vtty = s_loader.VisitType(lvd.Type);
								if(bbtyinfo.ContainsKey(lvnn))
									Contract.Assert(bbtyinfo[lvnn] == vtty, "Ok, we need to fix scoping");
								else
									bbtyinfo.Add(lvnn, vtty);
							}
						}
					}
				}

				bb.SetInScopeVars(bbscp, bbtyinfo);
			}
		}

		/// <summary>
		/// If the stack is not empty at a branch clear it and note what the remaining stack types were.
		/// </summary>
		private static void GenStackToVarDump(uint trgt, Dictionary<uint, List<IRType>> labelToTypeMap, Stack<IRType> cstack)
		{
			if(labelToTypeMap.ContainsKey(trgt) && labelToTypeMap[trgt].Count != cstack.Count)
				throw new InvalidOperationException("Stack is inconsistnent");

			bool fresh = false;
			if(!labelToTypeMap.ContainsKey(trgt))
			{
				fresh = true;
				labelToTypeMap.Add(trgt, new List<IRType>());
			}

			int i = 0;
			List<IRType> vexl = labelToTypeMap[trgt];
			Stack<IRType> restvals = new Stack<IRType>();
			while(cstack.Count != 0)
			{
				IRType sve = cstack.Pop();
				restvals.Push(sve);

				if(!fresh)
					Contract.Assert(sve == vexl[i], "Botched the type.");
				else
					vexl.Add(sve);

				++i;
			}

			while(restvals.Count != 0)
			{
				IRType restv = restvals.Pop();
				cstack.Push(restv);
			}
		}

		private static void ReloadStackDumpAtEntry(uint trgt, Dictionary<uint, List<IRType>> labelToTypeMap, Stack<IRType> cstack)
		{
			Contract.Assert(trgt == 0 || labelToTypeMap.ContainsKey(trgt), "Asside from entry this should always hold");

			if(trgt == 0)
				return;

			List<IRType> vexl = labelToTypeMap[trgt];
			for(int i = vexl.Count - 1; i >= 0; --i)
				cstack.Push(vexl[i]);
		}

		/// <summary>
		/// Generate a object alloc op
		/// </summary>
		private static void GenObjAllocOp(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			IMethodReference tmethod = (IMethodReference)op.Value;

			IRType resty = s_loader.VisitType(tmethod.ContainingType);
			IRType ctype = CCILoader.StripTypeOfAllIndirection(resty);
			List<IRType> sigl = new List<IRType>();

			int rcpos = 0;
			foreach(IParameterTypeInformation pd in tmethod.Parameters)
			{
				IRType paramtype = s_loader.VisitType(pd.Type);
				if(pd.IsByReference)
					paramtype = s_irprog.TypeTable.InternReferenceTypeFor(paramtype);

				sigl.Add(paramtype);

				++rcpos;
				execTransStack.Pop();
			}

			IRInvokeSig conssig = s_irprog.InvokeTable.InternVirtualInvoke(".ctor", sigl);
			IRInvokeIdentity invid = s_irprog.InvokeTable.InternInvokeIdentity(ctype, conssig);
			
			IRAllocationOp alloc = new IRAllocationOp(invid, ConvertToIRLocation(op));
			currentBlock.Operations.Add(alloc);
			execTransStack.Push(resty);
		}

		/// <summary>
		/// If we have a call op generate the Invoke bytecode instruction, tmethod is the specified target method.
		/// </summary>
		private static void ExtractConstrainOp(IOperation op, ITypeReference constraintype, IMethodReference tmethod, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			IRType ootype;
			IRType cctype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(constraintype));

			List<IRType> sigl = new List<IRType>();
			foreach(IParameterTypeInformation pd in tmethod.Parameters)
			{
				IRType paramtype = s_loader.VisitType(pd.Type);

				if(pd.IsByReference)
					paramtype = s_irprog.TypeTable.InternReferenceTypeFor(paramtype);

				sigl.Add(paramtype);
			}

			string fmname = tmethod.Name.Value;
			IRVirtualInvoke vsig = s_irprog.InvokeTable.InternVirtualInvoke(fmname, sigl);

			if(cctype is IRClassType)
				ootype = s_irprog.TypeTable.InternPointerTypeFor(cctype);
			else
			{
				//If we have a generic parameter then we are in a type patch method and we know we have loaded all the type definitions 
				//before processing these methods -- since they are all static. Otherwise we may not have fully processed the type definition 
				//that we are constraining on so we need to look at what the CCI type def. It is ugly.
				bool defsmethod;
				
				if(constraintype is IGenericParameter)
					defsmethod = cctype.TypeDescription.AllImplMemberMethods.Contains(vsig);
				else
					defsmethod = constraintype.ResolvedType.Methods.Contains(tmethod);

				if(defsmethod)
					ootype = s_irprog.TypeTable.InternReferenceTypeFor(cctype);
				else
					ootype = s_irprog.TypeTable.InternPointerTypeFor(s_irprog.TypeTable.InternBoxedTypeFor((IRValueType)cctype));
			}

			IRType[] ptl = new IRType[tmethod.ParameterCount];
			for(int i = 0; i < tmethod.ParameterCount; ++i)
				ptl[i] = execTransStack.Pop();

			execTransStack.Pop();
			execTransStack.Push(ootype);

			Array.Reverse(ptl);
			for(int i = 0; i < tmethod.ParameterCount; ++i)
				execTransStack.Push(ptl[i]);

			currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.Constrain, ootype, tmethod.ParameterCount, ConvertToIRLocation(op)));
		}

		/// <summary>
		/// If we have a call op generate the Invoke bytecode instruction, tmethod is the specified target method.
		/// </summary>
		private static void ExtractCallOp(IOperation op, IMethodReference tmethod, bool specdef, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			IRType encltypr = s_loader.VisitType(tmethod.ContainingType);
			IRType enclty = CCILoader.StripTypeOfAllIndirection(encltypr);

			IRType defclass = null;
			if(specdef)
				defclass = enclty;
			
			IRType retty = s_loader.VisitType(tmethod.Type);

			List<IRType> sigl = new List<IRType>();
			foreach(IParameterTypeInformation pd in tmethod.Parameters)
			{
				IRType paramtype = s_loader.VisitType(pd.Type);

				if(pd.IsByReference)
					paramtype = s_irprog.TypeTable.InternReferenceTypeFor(paramtype);

				sigl.Add(paramtype);
			}

			int rcpos = 0;
			for(int i = sigl.Count - 1; i >= 0; --i)
			{
				IRType paramtype = sigl[i];
				++rcpos;
				execTransStack.Pop();
			}

			string fmname = tmethod.Name.Value;

			IRCallOp bivk;
			if(tmethod.IsStatic)
			{
				bool typepatchneeded = tmethod.ResolvedMethod.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.TypePatchNeededAttribute"));
				IRStaticInvoke sig = s_irprog.InvokeTable.InternStaticInvoke(defclass, fmname, sigl);
				bivk = IRCallOp.MakeStaticMethodCall(retty, sig, ConvertToIRLocation(op));
				IRInvokeIdentity iiv = s_irprog.InvokeTable.InternInvokeIdentity(defclass, sig);

				if(!typepatchneeded)
					s_loader.VisitInvokeIdentity(iiv, tmethod.ResolvedMethod, null);
				else
				{
					IRType patchtype;
					IMethodReference rmethod = DoTypePatch((ISpecializedMethodReference)tmethod, defclass, fmname, sigl, out patchtype);
					s_loader.VisitInvokeIdentity(iiv, rmethod.ResolvedMethod, patchtype);
				}
			}
			else
			{
				IRVirtualInvoke sig = s_irprog.InvokeTable.InternVirtualInvoke(fmname, sigl);
				IRType baseimpltype = CCILoader.StripTypeOfAllIndirection(s_loader.VisitType(tmethod.ContainingType));
				IRType recev = execTransStack.Pop();

				if(specdef)
					bivk = IRCallOp.MakeRestrictedVirtualCall(retty, baseimpltype, defclass, (IRVirtualInvoke)sig, defclass, ConvertToIRLocation(op));
				else
					bivk = IRCallOp.MakeVirtualCall(retty, baseimpltype, recev, (IRVirtualInvoke)sig, ConvertToIRLocation(op));
			}

			currentBlock.Operations.Add(bivk);
			if(bivk.ReturnType != s_irprog.TypeTable.VoidType)
				execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(bivk.ReturnType));
		}

		/// <summary>
		/// For the builtin equality and compare operations we need to specialize them on the generic argument type provided
		/// </summary>
		private static IMethodReference DoTypePatch(ISpecializedMethodReference tmethod, IRType defclass, String name, List<IRType> sigtypes, out IRType patchtype)
		{
			Contract.Assert(sigtypes.Count == 2 && sigtypes[0] == sigtypes[1]);
			int spsi = defclass.TypeName.IndexOf('<');
			int spsl = defclass.TypeName.LastIndexOf('>');
			string ptname = defclass.TypeName.Substring(spsi + 1, spsl - (spsi + 1));

			IRType insttype = s_irprog.LookupTypeForName(ptname);
			if(insttype is IRClassType)
				patchtype = s_irprog.TypeTable.InternPointerTypeFor(insttype);
			else
				patchtype = insttype;

			IParameterTypeInformation[] prma = tmethod.Parameters.ToArray();
			int overridesequals = CheckOverridesEquals(prma[0].Type);
			bool implementscompare = CheckImplementsCompareable(prma[0].Type);
			bool isnullable = insttype.TypeDescription.AllInheritsExtends.Any((IRType tt) => tt.TypeName.StartsWith("System.Nullable<"));
			Contract.Assert(!isnullable, "argh, nullable");

			IMethodReference nmref = null;
			if(name.Equals("DefaultEquals"))
			{
				if(insttype is IRClassType)
				{
					if(overridesequals == 0)
						nmref = s_loader.ObjectEqualityComparerDefaultByRef;
					else if(overridesequals == 1)
						nmref = s_loader.ObjectEqualityComparerWEQ;
					else
						nmref = s_loader.ObjectEqualityComparer;
				}
				else
				{
					if(overridesequals == 0)
						nmref = s_loader.StructEqualityComparerDefaultByValue;
					else if(overridesequals == 1)
						nmref = s_loader.StructEqualityComparerWEQ;
					else
						nmref = s_loader.StructEqualityComparer;
				}
			}
			else if(name.Equals("DefaultGetHashCode"))
			{
				if(insttype is IRClassType)
				{
					if(overridesequals == 0)
						nmref = s_loader.ObjectEqualityComparerDefaultByRef_HashCode;
					else if(overridesequals == 1)
						nmref = s_loader.ObjectEqualityComparerWEQ_HashCode;
					else
						nmref = s_loader.ObjectEqualityComparer_HashCode;
				}
				else
				{
					if(overridesequals == 0)
						nmref = s_loader.StructEqualityComparerDefaultByValue_HashCode;
					else if(overridesequals == 1)
						nmref = s_loader.StructEqualityComparerWEQ_HashCode;
					else
						nmref = s_loader.StructEqualityComparer_HashCode;
				}
			}
			else
			{
				if(!implementscompare)
				{
					patchtype = null;
					return tmethod;
				}

				if(insttype is IRClassType)
					nmref = s_loader.ObjectComparer;
				else
					nmref = s_loader.StructComparer;
			}

			return nmref;
		}

		/// <summary>
		/// return true if a given type overrides the equals method.
		/// </summary>
		private static int CheckOverridesEquals(ITypeReference trr)
		{
			if(trr.ToString().Equals("System.Object") || trr.ToString().Equals("System.ValueType"))
				return 2;

			int fc = -1;
			foreach(IMethodDefinition m in trr.ResolvedType.Methods)
			{
				bool iseq = (m.IsVirtual && m.Name.Value.Equals("Equals") && m.ParameterCount == 1);
				if(iseq)
				{
					IParameterDefinition prd = (m.Parameters.ToArray())[0];
					if(prd.Type.ToString().Equals(trr.ToString()))
						fc = Math.Max(fc, 1);
					else
					{
						Contract.Assert(prd.Type.ToString().Equals("System.Object"));
						fc = Math.Max(fc, 0);
					}
				}
			}

			if(fc != -1)
				return fc;

			foreach(ITypeReference baseType in trr.ResolvedType.BaseClasses)
			{
				int cob = CheckOverridesEquals(baseType);
				if(cob != 2)
					return cob;
			}

			return 0;
		}

		/// <summary>
		/// return true if a given type implements the compareto method.
		/// </summary>
		private static bool CheckImplementsCompareable(ITypeReference trr)
		{
			if(trr.ToString().Equals("System.Object") || trr.ToString().Equals("System.ValueType"))
				return false;

			bool iseq = trr.ResolvedType.Methods.Any((IMethodDefinition m) => m.IsVirtual && m.Name.Value.Equals("CompareTo") && m.ParameterCount == 1);
			if(iseq)
				return true;

			foreach(ITypeReference baseType in trr.ResolvedType.BaseClasses)
			{
				if(CheckImplementsCompareable(baseType))
					return true;
			}

			return false;
		}

		/// <summary>
		/// Handle the processing of a load arg operation.
		/// </summary>
		private static void GenLoadArgOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			IRVarExp ave = null;
			switch(op.OperationCode)
			{
				case OperationCode.Ldarg:
				case OperationCode.Ldarg_S:
					IParameterDefinition pd = (IParameterDefinition)op.Value;
					String aname = (String)pd.Name.Value;
					IRVarName argvn = s_irprog.InternNewLocalVar(aname);
					IRType argty = s_loader.VisitType(pd.Type);
					
					if(pd.IsByReference)
						argty = s_irprog.TypeTable.InternReferenceTypeFor(argty);

					ave = new IRVarExp(argty, argvn);
					break;
				case OperationCode.Ldarg_0:
					ave = ComputeVarExpFromArgIndex(0);
					break;
				case OperationCode.Ldarg_1:
					ave = ComputeVarExpFromArgIndex(1);
					break;
				case OperationCode.Ldarg_2:
					ave = ComputeVarExpFromArgIndex(2);
					break;
				case OperationCode.Ldarg_3:
					ave = ComputeVarExpFromArgIndex(3);
					break;
				default:
					throw new ArgumentException("Bad Arg Operation");
			}

			currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeVarLoadOperation(ave.Name, ConvertToIRLocation(op)));
			execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(ave.VarType));
		}

		/// <summary>
		/// Handle the processing of a load arg address operation.
		/// </summary>
		private static void GenLoadArgAddressOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			IParameterDefinition pd = (IParameterDefinition)op.Value;
			String aname = (String)pd.Name.Value;
			IRVarName argvn = s_irprog.InternNewLocalVar(aname);
			IRType argty = s_loader.VisitType(pd.Type);
			IRVarExp ave = new IRVarExp(argty, argvn);

			currentBlock.Operations.Add(IRPointerIndexOp.MakeLoadLocalAddr(ave.Name, ConvertToIRLocation(op)));
			execTransStack.Push(s_irprog.TypeTable.InternReferenceTypeFor(ave.VarType));
		}

		/// <summary>
		/// Handle the processing of a store arg operation.
		/// </summary>
		private static void GenStoreArgOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			String aname = null;
			IRType atype = null;
			switch(op.OperationCode)
			{
				case OperationCode.Starg:
				case OperationCode.Starg_S:
					IParameterDefinition pd = (IParameterDefinition)op.Value;
					aname = (String)pd.Name.Value;
					atype = s_loader.VisitType(pd.Type);
					
					if(pd.IsByReference)
						atype = s_irprog.TypeTable.InternReferenceTypeFor(atype);

					break;
				default:
					throw new ArgumentException("Bad Arg Operation");
			}

			IRVarName argv = s_irprog.InternNewLocalVar(aname);
			execTransStack.Pop();

			currentBlock.Operations.Add(IRStoreFromEvalStackBasic.MakeVarStoreOperation(argv, ConvertToIRLocation(op)));
		}

		/// <summary>
		/// Given an index of an argument position compute the irvarex pfor it.
		/// </summary>
		private static IRVarExp ComputeVarExpFromArgIndex(int argidx)
		{
			IRType tt;
			if(s_currInvoke.Sig.IsVirtualInvoke)
			{
				if(argidx == 0)
				{
					if(s_currInvoke.DefInClass is IRValueType)
						tt = s_irprog.TypeTable.InternReferenceTypeFor(s_currInvoke.DefInClass);
					else
						tt = s_irprog.TypeTable.InternPointerTypeFor(s_currInvoke.DefInClass);
				}
				else
					tt = s_currInvoke.Sig.InvokeSig[argidx - 1];
			}
			else
				tt = s_currInvoke.Sig.InvokeSig[argidx];

			IRVarName argn = null;
			if(argidx == 0 && s_currInvoke.Sig.IsVirtualInvoke)
				argn = s_irprog.InternNewLocalVar("this");
			else
			{
				if(s_currInvoke.Sig.IsVirtualInvoke)
					argidx -= 1;

				foreach(IParameterDefinition pd in s_currMethod.Parameters)
				{
					if(argidx == 0)
					{
						String pname = pd.Name.Value;
						argn = s_irprog.InternNewLocalVar(pname);
						break;
					}
					--argidx;
				}
			}

			return new IRVarExp(tt, argn);
		}

		/// <summary>
		/// Generate the effects for load from a local variable.
		/// </summary>
		private static void GenLoadLocalOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			int loc = 0;
			switch(op.OperationCode)
			{
				case OperationCode.Ldloc:
				case OperationCode.Ldloc_S:
					String ldd = ((ILocalDefinition)op.Value).Name.Value;
					int spos = ldd.IndexOf('_');
					String spv = ldd.Substring(spos + 1);
					loc = Int32.Parse(spv);
					break;
				case OperationCode.Ldloc_0:
					loc = 0;
					break;
				case OperationCode.Ldloc_1:
					loc = 1;
					break;
				case OperationCode.Ldloc_2:
					loc = 2;
					break;
				case OperationCode.Ldloc_3:
					loc = 3;
					break;
				default:
					throw new ArgumentException("Unknown Load Op");
			}


			IRVarExp fve = ComputeVarExpFromLocalIndex(loc);
			currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeVarLoadOperation(fve.Name, ConvertToIRLocation(op)));
			execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(fve.VarType));
		}

		/// <summary>
		/// Generate the effects for load address of a local variable.
		/// </summary>
		private static void GenLoadLocalAddressOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			int loc = 0;
			String ldd = ((ILocalDefinition)op.Value).Name.Value;
			int spos = ldd.IndexOf('_');
			String spv = ldd.Substring(spos + 1);
			loc = Int32.Parse(spv);

			IRVarExp fve = ComputeVarExpFromLocalIndex(loc);
			currentBlock.Operations.Add(IRPointerIndexOp.MakeLoadLocalAddr(fve.Name, ConvertToIRLocation(op)));
			IRReferenceType rtt = s_irprog.TypeTable.InternReferenceTypeFor(fve.VarType);
			execTransStack.Push(rtt);
		}

		/// <summary>
		/// Handle the processing of a store local operation.
		/// </summary>
		private static void GenStoreLocalOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			int lpos = -1;
			switch(op.OperationCode)
			{
				case OperationCode.Stloc:
				case OperationCode.Stloc_S:
					String ldd = ((ILocalDefinition)op.Value).Name.Value;
					int spos = ldd.IndexOf('_');
					String spv = ldd.Substring(spos + 1);
					lpos = Int32.Parse(spv);
					break;
				case OperationCode.Stloc_0:
					lpos = 0;
					break;
				case OperationCode.Stloc_1:
					lpos = 1;
					break;
				case OperationCode.Stloc_2:
					lpos = 2;
					break;
				case OperationCode.Stloc_3:
					lpos = 3;
					break;
				default:
					throw new ArgumentException("Bad Local Operation");
			}

			IRVarExp slv = ComputeVarExpFromLocalIndex(lpos);
			execTransStack.Pop();

			currentBlock.Operations.Add(IRStoreFromEvalStackBasic.MakeVarStoreOperation(slv.Name, ConvertToIRLocation(op)));
		}

		/// <summary>
		/// Given an index of an local var compute the irvarex for it.
		/// </summary>
		private static IRVarExp ComputeVarExpFromLocalIndex(int locidx)
		{
			ILocalDefinition md = null;
			foreach(ILocalDefinition ldd in s_currMethod.Body.LocalVariables)
			{
				int spos = ldd.Name.Value.IndexOf('_');
				String spv = ldd.Name.Value.Substring(spos + 1);
				uint vv = UInt32.Parse(spv);
				if(vv == locidx)
				{
					md = ldd;
					break;
				}
			}

			Contract.Assert(md != null, "Missing Def??");
			bool compgen;
			String cpn = s_currpdb.GetSourceNameFor(md, out compgen);
			IRVarName mtsavn = s_irprog.InternNewLocalVar(cpn);
			IRType etype = s_loader.VisitType(md.Type);
			IRVarExp fve = new IRVarExp(etype, mtsavn);

			return fve;
		}

		private static void GenStoreIndirectOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			IRType sty = null;
			switch(op.OperationCode)
			{
				case OperationCode.Stind_I:
					throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
				case OperationCode.Stind_I1:
					sty = s_irprog.TypeTable.Int8Type;
					break;
				case OperationCode.Stind_I2:
					sty = s_irprog.TypeTable.Int16Type;
					break;
				case OperationCode.Stind_I4:
					sty = s_irprog.TypeTable.Int32Type;
					break;
				case OperationCode.Stind_I8:
					sty = s_irprog.TypeTable.Int64Type;
					break;
				case OperationCode.Stind_R4:
					sty = s_irprog.TypeTable.Float32Type;
					break;
				case OperationCode.Stind_R8:
					sty = s_irprog.TypeTable.Float64Type;
					break;
				case OperationCode.Stind_Ref:
					sty = s_loader.VisitType((ITypeReference)op.Value);
					break;
				case OperationCode.Stobj:
					sty = s_loader.VisitType((ITypeReference)op.Value);
					break;
				default:
					throw new ArgumentException("Bad Indirect Store");
			}

			execTransStack.Pop();
			execTransStack.Pop();

			IRReferenceType reftt = s_irprog.TypeTable.InternReferenceTypeFor(sty);
			currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeStoreIndirectOperation(reftt, ConvertToIRLocation(op)));
		}

		private static void GenLoadIndirectOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			execTransStack.Pop();
			IRType ldty = null;

			switch(op.OperationCode)
			{
				case OperationCode.Ldind_I:
					throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
				case OperationCode.Ldind_I1:
					ldty = s_irprog.TypeTable.Int8Type;
					break;
				case OperationCode.Ldind_I2:
					ldty = s_irprog.TypeTable.Int16Type;
					break;
				case OperationCode.Ldind_I4:
					ldty = s_irprog.TypeTable.Int32Type;
					break;
				case OperationCode.Ldind_I8:
					ldty = s_irprog.TypeTable.Int64Type;
					break;
				case OperationCode.Ldind_U1:
					ldty = s_irprog.TypeTable.UInt8Type;
					break;
				case OperationCode.Ldind_U2:
					ldty = s_irprog.TypeTable.UInt16Type;
					break;
				case OperationCode.Ldind_U4:
					ldty = s_irprog.TypeTable.UInt32Type;
					break;
				case OperationCode.Ldind_R4:
					ldty = s_irprog.TypeTable.Float32Type;
					break;
				case OperationCode.Ldind_R8:
					ldty = s_irprog.TypeTable.Float64Type;
					break;
				case OperationCode.Ldind_Ref:
					ldty = s_loader.VisitType((ITypeReference)op.Value);
					break;
				case OperationCode.Ldobj:
					ldty = s_loader.VisitType((ITypeReference)op.Value);
					break;
			}

			IRReferenceType reftt = s_irprog.TypeTable.InternReferenceTypeFor(ldty);
			currentBlock.Operations.Add(IRLoadToEvalStackIndirect.MakeLoadIndirectOperation(reftt, ConvertToIRLocation(op)));
			execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(ldty));
		}

		/// <summary>
		/// Generate the operations for an array load.
		/// </summary>
		private static void GenLoadArrayOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			execTransStack.Pop();

			IRPtrType rcvrty = (IRPtrType)execTransStack.Pop();
			IRContainerType ae = (IRContainerType)rcvrty.PtrTargetType;
			IRType loadty;

			switch(op.OperationCode)
			{
				case OperationCode.Ldelem:
					loadty = s_loader.VisitType((ITypeReference)op.Value);
					break;
				case OperationCode.Ldelem_I:
					throw new ArgumentException("Unsupported Opcode: " + op.OperationCode.ToString());
				case OperationCode.Ldelem_I1:
					loadty = s_irprog.TypeTable.Int8Type;
					break;
				case OperationCode.Ldelem_I2:
					loadty = s_irprog.TypeTable.Int16Type;
					break;
				case OperationCode.Ldelem_I4:
					loadty = s_irprog.TypeTable.Int32Type;
					break;
				case OperationCode.Ldelem_I8:
					loadty = s_irprog.TypeTable.Int64Type;
					break;
				case OperationCode.Ldelem_U1:
					loadty = s_irprog.TypeTable.UInt8Type;
					break;
				case OperationCode.Ldelem_U2:
					loadty = s_irprog.TypeTable.UInt16Type;
					break;
				case OperationCode.Ldelem_U4:
					loadty = s_irprog.TypeTable.UInt32Type;
					break;
				case OperationCode.Ldelem_R4:
					loadty = s_irprog.TypeTable.Float32Type;
					break;
				case OperationCode.Ldelem_R8:
					loadty = s_irprog.TypeTable.Float64Type;
					break;
				case OperationCode.Ldelem_Ref:
					loadty = ae.ContainerContentsType;
					break;
				default:
					throw new ArgumentException("Bad Array Load");
			}

			currentBlock.Operations.Add(IRLoadToEvalStackIndirect.MakeLoadArrayOperation(ae, ConvertToIRLocation(op)));
			execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(loadty));
		}

		/// <summary>
		/// Generate the operations for an array store.
		/// </summary>
		private static void GenStoreArrayOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			execTransStack.Pop();
			execTransStack.Pop();

			IRPtrType rcvrty = (IRPtrType)execTransStack.Pop();
			IRContainerType ae = (IRContainerType)rcvrty.PtrTargetType;

			currentBlock.Operations.Add(IRStoreFromEvalStackIndirect.MakeArrayStoreOperation(ae, ConvertToIRLocation(op)));
		}

		/// <summary>
		/// Generate the operations for an array length call.
		/// </summary>
		private static void GenArrayLengthOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			IRPtrType rcvrty = (IRPtrType)execTransStack.Pop();
			IRContainerType ae = (IRContainerType)rcvrty.PtrTargetType;
			
			currentBlock.Operations.Add(IRLoadToEvalStackIndirect.MakeArrayLengthOperation(ConvertToIRLocation(op)));

			execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
		}

		/// <summary>
		/// Generate the il for loading scalar integer constants.
		/// </summary>
		private static void GenLoadConstIntOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			long ival = Int32.MinValue;
			switch(op.OperationCode)
			{
				case OperationCode.Ldc_I4:
				case OperationCode.Ldc_I4_S:
					ival = (int)op.Value;
					break;
				case OperationCode.Ldc_I8:
					ival = (long)op.Value;
					break;
				case OperationCode.Ldc_I4_M1:
					ival = -1;
					break;
				case OperationCode.Ldc_I4_0:
					ival = 0;
					break;
				case OperationCode.Ldc_I4_1:
					ival = 1;
					break;
				case OperationCode.Ldc_I4_2:
					ival = 2;
					break;
				case OperationCode.Ldc_I4_3:
					ival = 3;
					break;
				case OperationCode.Ldc_I4_4:
					ival = 4;
					break;
				case OperationCode.Ldc_I4_5:
					ival = 5;
					break;
				case OperationCode.Ldc_I4_6:
					ival = 6;
					break;
				case OperationCode.Ldc_I4_7:
					ival = 7;
					break;
				case OperationCode.Ldc_I4_8:
					ival = 8;
					break;
				default:
					throw new ArgumentException("Missing Case in Load Scalar Const.");
			}

			IRLiteralExp lit = IRLiteralExp.MakeSignedIntegralLiteral(s_irprog.TypeTable.Int64Type, ival);
			currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeLoadConstOperation(lit, ConvertToIRLocation(op)));

			execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Int64Type));
		}

		/// <summary>
		/// Generate the il for loading scalar float constants.
		/// </summary>
		private static void GenLoadConstFloatOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			Contract.Assert(op.OperationCode == OperationCode.Ldc_R4 || op.OperationCode == OperationCode.Ldc_R8);
			
			IRLiteralExp lit;
			if(op.OperationCode == OperationCode.Ldc_R4)
			{
				float dv = (float)op.Value;
				lit = IRLiteralExp.MakeFloatLiteral(s_irprog.TypeTable.Float32Type, dv);
			}
			else
			{
				double dv = (double)op.Value;
				lit = IRLiteralExp.MakeFloatLiteral(s_irprog.TypeTable.Float64Type, dv);
			}

			currentBlock.Operations.Add(IRLoadToEvalStackBasic.MakeLoadConstOperation(lit, ConvertToIRLocation(op)));

			execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.Float64Type));
		}

		/// <summary>
		/// Generate the il for loading a static member function constants.
		/// </summary>
		private static void GenLoadStaticFunctionOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			Contract.Assert(op.OperationCode == OperationCode.Ldftn);

			IMethodReference tmethod = (IMethodReference)op.Value;
			IRType defclasspr = s_loader.VisitType(tmethod.ContainingType);
			IRType defclass =  CCILoader.StripTypeOfAllIndirection(defclasspr);
			
			IRType retty = s_loader.VisitType(tmethod.Type);

			String mname = tmethod.Name.Value;
			List<IRType> sigl = new List<IRType>();

			foreach(IParameterTypeInformation pd in tmethod.Parameters)
			{
				IRType paramtype = s_loader.VisitType(pd.Type);

				if(pd.IsByReference)
					paramtype = s_irprog.TypeTable.InternReferenceTypeFor(paramtype);

				sigl.Add(paramtype);
			}

			IRInvokeSig sig;
			IRInvokeIdentity iiv;
			if(tmethod.ResolvedMethod.IsStatic)
			{
				sig = s_irprog.InvokeTable.InternStaticInvoke(defclass, mname, sigl);
				iiv = s_irprog.InvokeTable.InternInvokeIdentity(defclass, sig);
			
				s_loader.VisitInvokeIdentity(iiv, tmethod.ResolvedMethod, null);
			}
			else
			{
				sig = s_irprog.InvokeTable.InternVirtualInvoke(mname, sigl);
				iiv = s_irprog.InvokeTable.InternInvokeIdentity(defclass, sig);
			}
			
			IRLoadToEvalStackBasic ldftn = IRLoadToEvalStackBasic.MakeFunctionLoadOperation(iiv, ConvertToIRLocation(op));

			currentBlock.Operations.Add(ldftn);
			execTransStack.Push(s_irprog.ConvertTypeToStdStackRep(s_irprog.TypeTable.FunctionPtrType));
		}

		private static void GenUnBoxOperation(IOperation op, Stack<IRType> execTransStack, IRBasicBlock currentBlock)
		{
			IRValueType vty = (IRValueType)s_loader.VisitType((ITypeReference)op.Value);
			IRType reftoboxty = s_irprog.TypeTable.InternReferenceTypeFor(vty);

			IRType tt = execTransStack.Pop();
			Contract.Assert(tt is IRBoxedType, "not a boxed type");
			currentBlock.Operations.Add(new IREvalStackTypeOp(OpCode.Op.UnBox, vty, -1, ConvertToIRLocation(op)));
			execTransStack.Push(tt);
		}

		/// <summary>
		/// Take a metadata expression that has a list of strings representing static fields as the value and parse them into sfl.
		/// </summary>
		private static void ExtractAdditionalStatics(IMetadataExpression smde, List<IRStaticField> sfl)
		{
			String val = (String)((IMetadataConstant)smde).Value;
			char[] seps = { ' ' };
			String[] spl = val.Split(seps);

			foreach(String ss in spl)
			{
				IRStaticField sf = s_loader.ResolveStaticFieldRefFromString(ss);
				sfl.Add(sf);
			}
		}

		/// <summary>
		/// Get the metadata expression corresponding to the value, return null if no such attribute is defined.
		/// </summary>
		private static IMetadataExpression FetchMethodAttributeIfPossible(IMethodDefinition methodDefinition, String attrstr)
		{
			ICustomAttribute ca = methodDefinition.Attributes.FirstOrDefault((ICustomAttribute attr) => attr.Type.ToString().Equals(attrstr));
			if(ca == null)
				return null;

			return ca.Arguments.ElementAt(0);
		}
	}
}
